/*
============================================================================
 Name        : dd_utf8.c
 Author      : Jian
 Version     :
 Copyright   : GPL
 Description : dd_utf8.c - source file
============================================================================
*/

/* INCLUDE FILES */
#include "dd_utf8.h"
#include "dd_log.h"

int _ucs2_to_utf8_single(DD_WCHAR ucs2, DD_BYTE* utf8, DD_UINT leftLen)
{
    if (ucs2 < 0x80) {
        if (leftLen < 1)
            return -1;

        if (ucs2 == 0) {
            utf8[0] = 0;
            return 0;
        }

        utf8[0] = ucs2;
        return 1;
    }

    if (ucs2 >= 0x80  && ucs2 < 0x800) {
        if ( leftLen < 2 )
            return -1;

        utf8[0] = (ucs2 >> 6)   | 0xC0;
        utf8[1] = (ucs2 & 0x3F) | 0x80;
        utf8[2] = '\0';
        return 2;
    }

    if (ucs2 >= 0x800 && ucs2 < 0xFFFF) {
        if (leftLen < 3)
            return -1;

        utf8[0] = ((ucs2 >> 12)       ) | 0xE0;
        utf8[1] = ((ucs2 >> 6 ) & 0x3F) | 0x80;
        utf8[2] = ((ucs2      ) & 0x3F) | 0x80;
        utf8[3] = '\0';
        return 3;
    }

    return -1;
}

int _ucs2_to_utf8(DD_BYTE *pUcs2, DD_BYTE *pUtf8, DD_BOOL isLE)
{
    DD_WCHAR ucs2 ;
    int      len = 0 ;
    int      utf8Len = 0 ;

    while(1) {
        if (isLE)
            ucs2 = *pUcs2 + ((*(pUcs2 + 1)) << 8) ;
        else 
            ucs2 = *(pUcs2 + 1) + ((*pUcs2) << 8) ;

        len = _ucs2_to_utf8_single(ucs2, pUtf8, 4);

        if (len <= 0)
            return utf8Len;

        pUtf8 += len;
        utf8Len +=len;
        pUcs2 +=2;
    }
}

int _utf8_to_ucs2_single(const DD_BYTE *input, DD_WCHAR *output, DD_UINT len)
{
    if (input[0] < 0x80) {
        *output = input[0];

        return (input[0] == 0) ? 0 : 1 ;
    }

    if ((input[0] & 0xE0) == 0xE0) {
        if (len < 3)
            return -1;

        *output = (( input[0] & 0x0F) << 12 ) | ( (input[1] & 0x3F) << 6 )  | (input[2] & 0x3F);
        return 3;
    }

    if ((input[0] & 0xC0) == 0xC0) {
        if (len < 2)
            return -1;

        *output = ((input[0] & 0x1F) << 6) | (input[1] & 0x3F);
        return 2;
    }

    return -1;
}

int  _utf8_to_ucs2(DD_BYTE *input, DD_UINT len, DD_BYTE* output, DD_UINT* outputLen)
{
    int      leftLen = len;
    int      ret;
    DD_BYTE* pUtf8 = input ;
    DD_BYTE* pUcs2 = output;

    while(leftLen > 0) {
        ret = _utf8_to_ucs2_single(pUtf8, (DD_WCHAR*)pUcs2, leftLen);
        if (ret < 0)
            break;

        if (ret == 0)
            ret = 1;

        pUtf8 += ret;
        pUcs2 += 2;

        leftLen -= ret;
    }
    
    if (outputLen)
        *outputLen = pUcs2 - output;

    return pUtf8 - input;
}

DD_UTF8* dd_ucs2_to_utf8(const DD_WCHAR* ucs2) 
{
    int      len = 0 ;
    DD_UTF8* utf8 = NULL ;
    
    __DD_ASSERT_DEFENSE(ucs2, return NULL) ; 

    len = dd_usc2_len(ucs2) ;

    utf8 = (DD_UTF8*)dd_malloc((len + 1) * 3) ;
    __DD_CHECK_MEM(utf8, (len + 1) * 3, return NULL) ;

    _ucs2_to_utf8((DD_BYTE*)ucs2, utf8, DD_TRUE) ;

    return utf8 ;
}

DD_UTF8* dd_ucs2_be_to_utf8(const DD_WCHAR* beUcs2) 
{
    int      len = 0 ;
    DD_UTF8* utf8 = NULL ;

    __DD_ASSERT_DEFENSE(beUcs2, return NULL) ; 

    len = dd_usc2_len(beUcs2) ;

    utf8 = (DD_UTF8*)dd_malloc((len + 1) * 3) ;
    __DD_CHECK_MEM(utf8, (len + 1) * 3, return NULL) ;

    _ucs2_to_utf8((DD_BYTE*)beUcs2, utf8, DD_FALSE) ;

    return utf8 ;
}

DD_WCHAR* dd_utf_to_ucs2(const DD_UTF8* utf8) 
{
    int       numLen  = 0 ;
    DD_WCHAR* uniData = NULL ;

    __DD_ASSERT_DEFENSE(utf8, return NULL) ; 

    numLen = strlen((const char*)utf8) ;

    uniData = (DD_WCHAR*)dd_malloc((numLen + 1) * 2) ;
    __DD_CHECK_MEM(uniData, (numLen + 1) * 2, return NULL) ;

    _utf8_to_ucs2((DD_BYTE*)utf8, numLen, (DD_BYTE*)uniData, NULL) ;

    return uniData ;
}

int dd_usc2_len(const DD_WCHAR* ucs2)
{
    int len = 0;

    __DD_ASSERT_DEFENSE(ucs2, NULL) ;

    while ((*ucs2 != 0) || (*(ucs2+1) != 0)) {
        ucs2 += 2;
        len++;
    }

    return len;
}

const DD_WCHAR* dd_ucs2chr(const DD_WCHAR* ucs2, DD_WCHAR chr) 
{
    __DD_ASSERT_DEFENSE(ucs2, return NULL) ;
    dd_ucs2chr_by_len(ucs2, dd_usc2_len(ucs2), chr) ;      
}

const DD_WCHAR* dd_ucs2chr_by_len(const DD_WCHAR* ucs2, int len, DD_WCHAR chr) 
{
    const DD_BYTE* loop = (const DD_BYTE*)ucs2 ;
    int i = 0 ;

    __DD_ASSERT_DEFENSE(ucs2 && len < 0, return NULL) ;

   for (; i < len; i++) {
       if (*loop == (chr >> 8) && *(loop + 1) == (chr & 0xFF))
           return (const DD_WCHAR*)loop ;
    
       loop += 2 ;
   }

   return NULL ;
}

/* End of File */
